package com.sharelords.demo.common.base.client.impl;

import com.sharelords.biz.Biz;
import com.sharelords.demo.common.base.client.BaseClient;
import com.sharelords.demo.common.enums.ReturnCodeEnum;
import com.sharelords.demo.common.enums.YesOrNoEnum;
import com.sharelords.demo.common.result.ServiceResult;
import com.sharelords.demo.common.result.helper.ServiceResultHelper;
import com.sharelords.demo.common.util.InvokeUtil;
import com.sharelords.demo.common.util.ObjectClassInvoke;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.persistence.Id;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * @Description: 通用facade层工具，更新数据时需传入主键，ao对应主键属性，以@Id标记
 *
 * @Author: 千古龙少
 * @Time: 2019/12/7 20:01
 */
public class BaseFacadeImpl<Ao, Bo, D, Service extends Biz<Bo, ?, D, ?>> implements BaseClient<Ao, D> {
	
	private static Logger logger = LoggerFactory.getLogger(BaseFacadeImpl.class);
	
	private Class<Ao> aoClass;
	private Class<Bo> boClass;
	
	/**
	 * 主键对应的字段
	 */
	private Field primaryField;

	@Autowired
	private Service biz;
	
	@SuppressWarnings("unchecked")
	public BaseFacadeImpl() {
		// 得到父类的泛型
		Type sType = getClass().getGenericSuperclass();
		// 得到实际的类型参数数组
		Type[] generics = ((ParameterizedType) sType).getActualTypeArguments();
		// 得到第一个泛型的Class
		aoClass = (Class<Ao>) generics[0];
		// 得到第二个泛型的Class
		boClass = (Class<Bo>) generics[1];
		// 获取主键字段
		primaryField = ObjectClassInvoke.getFieldOfAno(aoClass, Id.class);
	}
	
	@Override
	public ServiceResult<Integer> save(Ao ao) {
		return this.commonSaveMethod(ao, YesOrNoEnum.YES);
	}

	@Override
	public ServiceResult<Integer> saveSelective(Ao ao) {
		return this.commonSaveMethod(ao, YesOrNoEnum.NO);
	}
	
	@Override
	public ServiceResult<Integer> update(Ao ao) {
		return this.commonUpdateMethod(ao, YesOrNoEnum.YES);
	}
	
	@Override
	public ServiceResult<Integer> updateSelective(Ao ao) {
		return this.commonUpdateMethod(ao, YesOrNoEnum.NO);
	}
	
	@Override
	public ServiceResult<Integer> deletePhysically(D d) {
		if (d == null) {
			return ServiceResultHelper.fail(ReturnCodeEnum.PARAM_BLANK);
		}
		
		try {
			// 根据主键获取记录
			Bo existBo = biz.queryByPrimaryKey(d);
			if (existBo == null) {
				// 记录不存在
				return ServiceResultHelper.fail(ReturnCodeEnum.RECORD_NOT_EXIST);
			}
			
			// 执行更新操作
			Integer deleteCount = biz.deletePhysically(d);
			if (deleteCount == null || deleteCount != 1) {
				return ServiceResultHelper.fail(ReturnCodeEnum.FAILED);
			}
			
			return ServiceResultHelper.success(deleteCount);
		} catch (Exception e) {
			logger.error("删除记录发生异常，主键id={}，异常信息为：{}", d, e);
			return ServiceResultHelper.fail(ReturnCodeEnum.ERROR);
		}
	}

	@Override
	public ServiceResult<Ao> queryByPrimaryKey(D d) {
		if (d == null) {
			return ServiceResultHelper.fail(ReturnCodeEnum.PARAM_BLANK);
		}
		
		try {
			// 执行查询
			Bo bo = biz.queryByPrimaryKey(d);
			// 数据封装及返回
			return ServiceResultHelper.success(InvokeUtil.copy(bo, aoClass));
		} catch (Exception e) {
			logger.error("根据主键获取记录发生异常，主键={}，异常信息为：{}", d, e);
			return ServiceResultHelper.fail(ReturnCodeEnum.ERROR);
		}
	}

	@Override
	public ServiceResult<List<Ao>> queryByAo(Ao ao) {
		if (ao == null) {
			return ServiceResultHelper.fail(ReturnCodeEnum.PARAM_BLANK);
		}
		
		try {
			// 执行查询
			List<Bo> boList = biz.queryByBo(InvokeUtil.copy(ao, boClass));
			// 数据封装及返回
			return ServiceResultHelper.success(InvokeUtil.copyList(boList, aoClass));
		} catch (Exception e) {
			logger.error("多条件获取记录列表发生异常，参数为：{}，异常信息为：{}", ao, e);
			return ServiceResultHelper.fail(ReturnCodeEnum.ERROR);
		}
	}

	@Override
	public ServiceResult<List<Ao>> queryAll() {
		try {
			// 执行查询
			List<Bo> boList = biz.queryAll();
			// 数据封装及返回
			return ServiceResultHelper.success(InvokeUtil.copyList(boList, aoClass));
		} catch (Exception e) {
			logger.error("获取所有子订单信息发生异常，异常信息为：", e);
			return ServiceResultHelper.fail(ReturnCodeEnum.ERROR);
		}
	}

	@Override
	public ServiceResult<List<Ao>> queryReCordsByIdList(List<D> idList) {
		if (idList == null || idList.isEmpty()) {
			return ServiceResultHelper.fail(ReturnCodeEnum.PARAM_BLANK);
		}
		
		try {
			List<Bo> boList = biz.queryReCordsByIdList(idList);
			return ServiceResultHelper.success(InvokeUtil.copyList(boList, aoClass));
		} catch (Exception e) {
			logger.error("根据id批量获取子订单信息列表发生异常，异常信息为：", e);
			return ServiceResultHelper.fail(ReturnCodeEnum.ERROR);
		}
	}
	
	/**
	 * 通用新增方法
	 *
	 * @author 千古龙少
	 * @date 2019年9月25日 下午7:32:13
	 * @param ao 参数
	 * @param containNullFlag 是否包含null枚举，YES--包含，NO--不包含
	 * @return ServiceResult
	 */
	private ServiceResult<Integer> commonSaveMethod(Ao ao, YesOrNoEnum containNullFlag) {
		if (ao == null) {
			return ServiceResultHelper.fail(ReturnCodeEnum.PARAM_BLANK);
		}
		
		try {
			// 执行新增操作
			Bo bo = InvokeUtil.copy(ao, boClass);
			
			Integer saveCount;
			if (YesOrNoEnum.YES.equals(containNullFlag)) {
				// 保存全部字段
				saveCount = biz.save(bo);
			} else {
				// 保存非null字段
				saveCount = biz.saveSelective(bo);
			}
			if (saveCount == null || saveCount != 1) {
				return ServiceResultHelper.fail(ReturnCodeEnum.FAILED);
			}
			
			// 参数重新赋值（为了返回主键）
			BeanUtils.copyProperties(bo, ao);
			
			return ServiceResultHelper.success(saveCount);
		} catch (Exception e) {
			logger.error("新增记录发生异常，异常信息为：", e);
			return ServiceResultHelper.fail(ReturnCodeEnum.ERROR);
		}
	}
	
	/**
	 * 通用更新方法
	 *
	 * @author 千古龙少
	 * @date 2019年9月25日 下午7:37:49
	 * @param ao 参数
	 * @param containNullFlag 是否包含null枚举，YES--包含，NO--不包含
	 * @return ServiceResult
	 */
	private ServiceResult<Integer> commonUpdateMethod(Ao ao, YesOrNoEnum containNullFlag) {
		if (ao == null) {
			return ServiceResultHelper.fail(ReturnCodeEnum.PARAM_BLANK);
		}
		
		try {
			// 获取实例对应的主键属性名称
			@SuppressWarnings("unchecked")
			D primaryKey = (D) primaryField.get(ao);
			if (primaryKey == null) {
				// 无主键注解，返回空
				return ServiceResultHelper.fail(ReturnCodeEnum.PARAM_ERROR);
			}
			
			// 根据主键获取记录
			Bo existBo = biz.queryByPrimaryKey(primaryKey);
			if (existBo == null) {
				// 记录不存在
				return ServiceResultHelper.fail(ReturnCodeEnum.RECORD_NOT_EXIST);
			}
			
			// 执行更新操作
			Integer updateCount;
			if (YesOrNoEnum.YES.equals(containNullFlag)) {
				// 更新全部字段
				updateCount = biz.update(InvokeUtil.copy(ao, boClass));
			} else {
				// 更新非null字段
				updateCount = biz.updateSelective(InvokeUtil.copy(ao, boClass));
			}
			if (updateCount == null || updateCount != 1) {
				return ServiceResultHelper.fail(ReturnCodeEnum.FAILED);
			}
			
			return ServiceResultHelper.success(updateCount);
		} catch (Exception e) {
			logger.error("更新记录发生异常，异常信息为：", e);
			return ServiceResultHelper.fail(ReturnCodeEnum.ERROR);
		}
	}

}
